/**************************************************************************/
/*  EOSP                                                                  */
/*                                                                        */
/*  Copyright (c) 2013-2019                                               */
/*  All rights reserved.                                                  */
/*                                                                        */
/*  This project was developed by the SJQU Computer Department as part    */
/*  of the course 'Embedded Operation System Practice'.                   */
/*                                                                        */
/*  Redistribution and use in source and binary forms, with or without    */
/*  modification, are permitted provided that the following conditions    */
/*  are met:                                                              */
/*  1. Redistributions of source code must retain the above copyright     */
/*     notice, this list of conditions and the following disclaimer.      */
/*  2. Redistributions in binary form must reproduce the above copyright  */
/*     notice, this list of conditions and the following disclaimer in    */
/*     the documentation and/or other materials provided with the         */
/*     distribution.                                                      */
/*                                                                        */
/*  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''    */
/*  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED     */
/*  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A       */
/*  PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR   */
/*  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,          */
/*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES /INCLUDING, BUT NOT      */
/*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF      */
/*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION/ HOWEVER CAUSED AND   */
/*  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,    */
/*  OR TORT /INCLUDING NEGLIGENCE OR OTHERWISE/ ARISING IN ANY WAY OUT    */
/*  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF    */
/*  SUCH DAMAGE.                                                          */
/**************************************************************************/
#include "app_databuf.h"
#include <stdlib.h>
#include <string.h>

static void db_peek(struct databuf_typedef *databuf, char *peekbuf, int len)
{
  int tail = (databuf->tail + len) % databuf->size;
  if (tail >= databuf->tail) {
    memcpy(peekbuf, databuf->data + databuf->tail, len);
  } else {
    int left, right;
    right = (databuf->size - databuf->tail);
    left = len - right;
    memcpy(peekbuf, databuf->data + databuf->tail, right);
    memcpy(peekbuf + right, databuf->data, left);
  }
}

static void db_read(struct databuf_typedef *databuf, char *readbuf, int len)
{
  db_peek(databuf, readbuf, len);
  databuf->tail = (databuf->tail + len) % databuf->size;
}

static void db_write(struct databuf_typedef *databuf, const char *writebuf, int len)
{
  int head = (databuf->head + len) % databuf->size;
  if (head >= databuf->head) {
    memcpy(databuf->data + databuf->head, writebuf, len);
  } else {
    int left, right;
    right = (databuf->size - databuf->head);
    left = len - right;
    memcpy(databuf->data + databuf->head, writebuf, right);
    memcpy(databuf->data, writebuf + right, left);
  }
  databuf->head = head;
}

static void db_reset(struct databuf_typedef *databuf)
{
  databuf->head = databuf->tail = 0;
}

int db_size(struct databuf_typedef *databuf)
{
  return (databuf->head + databuf->size - databuf->tail) % databuf->size;  
}

databuf_pt create_databuf(void)
{
  databuf_pt pt = (databuf_pt)malloc(DATABUF_DEFAULT_SIZE);
  pt->size = DATABUF_DEFAULT_SIZE - sizeof(*pt);
  pt->head = pt->tail = 0;
  pt->peek = db_peek;
  pt->read = db_read;
  pt->write = db_write;
  pt->reset = db_reset;
  pt->dbsize = db_size;
  pt->data = (char*)pt + sizeof(*pt);
  return pt;
}

void destroy_databuf(databuf_pt pt)
{
  free(pt);
}
